package geditor {
import flash.display.DisplayObject;
import flash.events.Event;
import flash.geom.Point;

import geditor.common.AlignSource;
import geditor.common.DrawComponent;

import geditor.events.RedrawEvent;

import geditor.events.UnloadEvent;

import mx.containers.Canvas;

/**
 * Canvas, который содержит все компоненты
 */
public class DrawCanvas extends Canvas {
    /**
     * Canvas, у которого редактор сам меняет scale
     */
    internal var scalable:Canvas = new Canvas();

    /**
     * Canvas, чьи компоненты должны сами отрабатывать scale event
     */
    internal var notScalable:Canvas = new Canvas();

    internal var auxiliary:Canvas = new Canvas();

    internal var components:Array = [];

    private var _container:DrawTool;

    public function get container():DrawTool {
        return _container;
    }

    public function DrawCanvas(cont:DrawTool) {
        super();
        this._container = cont;
        scalable.clipContent = false;
        notScalable.clipContent = false;

        addChild(scalable);
        addChild(auxiliary);
        addChild(notScalable);

        notScalable.x = 50;
        notScalable.y = 50;

        scalable.x = 50;
        scalable.y = 50;
    }

    private var _scale:Number = 1;

    public function get scale():Number {
        return _scale;
    }

    private function refreshComponents():void {
        for each(var c:DrawComponent in components) {
            c.refresh();
        }
    }

    public function set scale(value:Number):void {
        var oldScale:Number = _scale;
        _scale = value;

        scalable.scaleX = _scale;
        scalable.scaleY = _scale;

        var children:Array = auxiliary.getChildren();
        for each (var child:DisplayObject in children) {
            var realOldX:Number = (child.x + child.width / 2 - 50) / oldScale;
            var realOldY:Number = (child.y + child.height / 2 - 50) / oldScale;

            positionHandle(child, new Point(realOldX, realOldY));
        }

        refreshComponents();
    }

    internal function positionHandle(handle:DisplayObject, p:Point):void {
        handle.x = (p.x) * scale - (handle.width / 2) + 50;
        handle.y = (p.y) * scale - (handle.height / 2) + 50;
    }

    public function removeComponent(comp:DrawComponent):void {
        components = CommonHelper.removeFromArray(components, components.indexOf(comp));

        if (comp.scalableDisplay != null) {
            scalable.removeChild(comp.scalableDisplay);
        }

        if (comp.notScalableDisplay != null) {
            notScalable.removeChild(comp.notScalableDisplay);
        }

        comp.dispatchEvent(new UnloadEvent());
    }

    /**
     * Добавляет компонент в коллекцию компонентов, учитывая z-index
     * @param comp
     * @return номер, на котором встал компонент
     */
    private function addToComponents(comp:DrawComponent):int {
        for (var i:int = 0; i < components.length; i++) {
            var dc:DrawComponent = DrawComponent(components[i]);
            if (dc.zIndex < comp.zIndex) {
                components = CommonHelper.addItemToArray(components, comp, i);
                return i;
            }
        }

        components.push(comp);
        return components.length - 1;
    }

    private function addScalableDisplay(pos:int, comp:DrawComponent):void {
        if (comp.scalableDisplay == null) return;

        //пробегаем по всем компонентам, которые должны быть ближе, чем вставляемый
        for (var i:int = pos - 1; i >= 0; i--) {
            var dc:DrawComponent = DrawComponent(components[i]);
            if (dc.scalableDisplay != null) {
                //вставить за ним
                var childIndex:int = scalable.getChildIndex(dc.scalableDisplay);
                scalable.addChildAt(comp.scalableDisplay, childIndex);
                return;
            }
        }

        //если не нашли такого, то вставляем самым близким
        scalable.addChild(comp.scalableDisplay);
    }

    private function addNotScalableDisplay(pos:int, comp:DrawComponent):void {
        if (comp.notScalableDisplay == null) return;

        //пробегаем по всем компонентам, которые должны быть ближе, чем вставляемый
        for (var i:int = pos - 1; i >= 0; i--) {
            var dc:DrawComponent = DrawComponent(components[i]);
            if (dc.notScalableDisplay != null) {
                //вставить за ним
                var childIndex:int = notScalable.getChildIndex(dc.notScalableDisplay);
                notScalable.addChildAt(comp.notScalableDisplay, childIndex);
                return;
            }
        }

        //если не нашли такого, то вставляем самым близким
        notScalable.addChild(comp.notScalableDisplay);
    }

    public function addComponent(comp:DrawComponent):void {
        var pos:int = addToComponents(comp);

        comp.tool = container;

        addScalableDisplay(pos, comp);
        addNotScalableDisplay(pos, comp);

        comp.dispatchEvent(new Event("load"));
        comp.dispatchEvent(new RedrawEvent());
    }

    /**
     * Возвращает список всех опубликованных объектов
     * @return Array
     */
    public function get published():Array {
        var res:Array = [];
        for each (var dc:DrawComponent in components) {
            if (dc is AlignSource) {
                if (AlignSource(dc).published != null)
                    res = res.concat(AlignSource(dc).published);
            }
        }

        return res;
    }

    //    override public function get top():int {
    //        return parseInt(getStyle("top"));
    //    }
    //
    //    public function get left():int {
    //        return parseInt(getStyle("left"));
    //    }
    //
    //    public function set top(val:int):void {
    //        setStyle("top", val);
    //    }
    //
    //    public function set left(val:int):void {
    //        setStyle("left", val);
    //    }
}
}